/* 
 * File:   CalculatorParser.h
 * Author: Gab'z
 *
 * Created on 27 mai 2012, 18:18
 */

#ifndef CALCULATORPARSER_H
#define	CALCULATORPARSER_H

#include "../model/Context.h"
#include "../exception/ParseException.h"
#include "../model/command/Command.h"
#include "../model/command/literal/Integer.h"
#include "../model/command/literal/Rationnal.h"
#include "../model/command/literal/Real.h"
#include "../model/command/literal/Complex.h"
#include "../model/command/literal/Expression.h"
#include "../log/LogSystem.h"

namespace calculator {

    /**
     * Parseur de l'application CalculatriceNPI.
     * Permet de passer d'une chaîne de caractères à une commande.
     * On obtient en général soit une commande, soit un nombre soit une expression.
     * Rappel : les nombres et expressions sont aussi des commandes.
     */
    class CalculatorParser {
    public:
        /**
         * Constructeur de CalculatorParser.
         * @param context le contexte courant dont on utilise le jeu de commandes fixes
         * ainsi que les commandes utilisateurs créées.
         */
        CalculatorParser(const Context * const context);

        /**
         * Detructeur de CalculatorParser.
         * Ne détruit pas le moteur de l'application
         */
        virtual ~CalculatorParser();

        /**
         * Fonction de parsage d'une chaîne de caractère en expression.
         * @param str la chaîne de caractère à convertir.
         * @return une commande, qui peut aussi être un nombre ou une expression.
         */
        const Command* parse(const std::string& str) const throw (ParseException);

        /**
         * Teste si une chaîne est parsable en Integer.
         * @param str la chaîne à tester.
         * @return true si str peut être un Integer, false sinon.
         */
        bool isInteger(const std::string& str) const;

        /**
         * Teste si une chaîne est parsable en Rationnal.
         * @param str la chaîne à tester.
         * @return true si str peut être un Rationnal, false sinon.
         */
        bool isRationnal(const std::string& str, int* pos = 0) const;

        /**
         * Teste si une chaîne est parsable en Real.
         * @param str la chaîne à tester.
         * @return true si str peut être un Real, false sinon.
         */
        bool isReal(const std::string& str, int* pos = 0) const;

        /**
         * Teste si une chaîne est parsable en Complex.
         * @param str la chaîne à tester.
         * @return true si str peut être un Complex, false sinon.
         */
        bool isComplex(const std::string& str, int* pos = 0) const;

        /**
         * Teste si une chaîne est parsable soit en un Integer, soit un Rationnal, soit un Real.
         * @param str la chaîne à tester.
         * @return true si str peut être un Integer, un Rationnal ou un Real, false sinon.
         */
        bool isSimpleNumber(const std::string& str) const;

        /**
         * Teste si un chaîne de caractère correspond à une Command du gestionnaire de commande.
         * @param str la chaîne à tester.
         * @return true si une occurence est trouvée, false sinon.
         */
        bool isCommand(const std::string& str) const;

        /**
         * Teste si une chaîne de caractères correspond à une expression.
         * @param str la chaîne à tester.
         * @return true si la châine est une expression, false sinon.
         * Une Expression commence par un ' et termine par un '.
         * Il ne peut y avoir d'Expression à l'intérieur d'une Expression,
         * une Expression est composée d'au moins une Command.
         */
        bool isExpression(const std::string& str) const;

    private:
        /**
         * Pointeur vers le contexte courant.
         * Ne peut pas être remplacé.
         */
        const Context * const _context;

        /**
         * Crée un Integer à partir d'une chaîne de caractères.
         * @param str la chaîne de caractères à transformer.
         * @return un Integer.
         */
        const Integer* makeInteger(const std::string& str) const;

        /**
         * Crée un Rationnal à partir d'une chaîne de caractères.
         * @param str la chaîne de caractères à transformer.
         * @return un Rationnal.
         */
        const Rationnal* makeRationnal(const std::string& str, int* pos) const;

        /**
         * Crée un Real à partir d'une chaîne de caractères.
         * @param str la chaîne de caractères à transformer.
         * @return un Real.
         */
        const Real* makeReal(const std::string& str, int* pos) const;
        
        /**
         * Crée soit un Integer, soit un Rationnal, soit un Réel à partir d'une chaîne de caractères.
         * @param str la chaîne de caractères à transformer.
         * @return un Integer.
         * Utilisé pour créer des nombres de type Complex.
         */
        const SimpleNumber* makeSimpleNumber(const std::string& str) const throw (ParseException);
        
        /**
         * Crée un Complex à partir d'une chaîne de caractères.
         * @param str la chaîne de caractères à transformer.
         * @return un Complex.
         */
        const Complex* makeComplex(const std::string& str, int* pos) const throw (ParseException);
       
        /**
         * Crée une Commande à partir d'une chaîne de caractères.
         * @param str la chaîne de caractères à transformer.
         * @return une Command parmis celle du gestionnaire de commandes,
         * utilisation du design pattern Prototype.
         */
        const Command* makeCommand(const std::string& str) const throw (ParseException);
        
        /**
         * Crée une Expression à partir d'une chaîne de caractères.
         * @param str la chaîne de caractères à transformer.
         * @return une Expression.
         * Fait appel aux autres méthodes de la classe CalculatorParser pour générer
         * ses composants.
         */
        const Expression* makeExpression(const std::string& str) const throw (ParseException);

        static Logger* log;
    };
}

#endif	/* CALCULATORPARSER_H */

